home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
090
/
less.arc
/
LESS.PT2
< prev
Wrap
Text File
|
1986-08-13
|
67KB
|
2,990 lines
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
# makefile.sys5
# makefile.xen
# mkfuncs.awk
# n10-diff
# option.c
# output.c
# pager_patch.c
# position.c
# position.h
# prim.c
# prompt.c
# screen.c
# signal.c
# ttyin.c
# version.c
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'makefile.sys5'
then
echo shar: "will not over-write existing file 'makefile.sys5'"
else
cat << \SHAR_EOF > 'makefile.sys5'
# Makefile for "less"
#
# Invoked as:
# make all
# or make install
# Plain "make" is equivalent to "make all".
#
# If you add or delete functions, remake funcs.h by doing:
# make newfuncs
# This depends on the coding convention of function headers looking like:
# " \t public <function-type> \n <function-name> ( ... ) "
#
# Also provided:
# make lint # Runs "lint" on all the sources.
# make clean # Removes "less" and the .o files.
# make clobber # Pretty much the same as make "clean".
#
# make pager_patch # makes PAGER environment variable
# make install_pager_patch # catcher and installs it (see below)
##########################################################################
# System-specific parameters
##########################################################################
# Define XENIX if running under XENIX 3.0
XENIX = 0
# VOID is 1 if your C compiler supports the "void" type,
# 0 if it does not.
VOID = 1
# off_t is the type which lseek() returns.
# It is also the type of lseek()'s second argument.
off_t = long
# TERMIO is 1 if your system has /usr/include/termio.h.
# This is normally the case for System 5.
# If TERMIO is 0 your system must have /usr/include/sgtty.h.
# This is normally the case for BSD.
TERMIO = 1
# SIGSETMASK is 1 if your system has the sigsetmask() call.
# This is normally the case only for BSD 4.2,
# not for BSD 4.1 or System 5.
SIGSETMASK = 0
##########################################################################
# Optional and semi-optional features
##########################################################################
# REGCMP is 1 if your system has the regcmp() function.
# This is normally the case for System 5.
# RECOMP is 1 if your system has the re_comp() function.
# This is normally the case for BSD.
# If neither is 1, pattern matching is supported, but without metacharacters.
REGCMP = 1
RECOMP = 0
# SHELL_ESCAPE is 1 if you wish to allow shell escapes.
# (This is possible only if your system supplies the system() function.)
SHELL_ESCAPE = 0
# EDITOR is 1 if you wish to allow editor invocation (the "v" command).
# (This is possible only if your system supplies the system() function.)
# EDIT_PGM is the name of the (default) editor to be invoked.
EDITOR = 0
EDIT_PGM = /usr/ucb/vi
# parameters to "make install_pager_patch". OLD_PAGER will be moved to
# OLD_PAGER_NEW_LOCATION and pager_patch (in this directory) will be installed
# as OLD_PAGER. This patch will allow you to set the environment variable
# PAGER to specify your personal pager preference (is this a security hole?)
OLD_PAGER = /usr/ucb/more
OLD_PAGER_NEW_LOCATION = /usr/ucb/More
# ONLY_RETURN is 1 if you want RETURN to be the only input which
# will continue past an error message.
# Otherwise, any key will continue past an error message.
ONLY_RETURN = 0
##########################################################################
# Compilation environment.
##########################################################################
# LIBS is the list of libraries needed.
LIBS = -lcurses -lPW
# INSTALL_LESS is a list of the public versions of less.
# INSTALL_MAN is a list of the public versions of the manual page.
INSTALL_LESS = /usr/lbin/less
INSTALL_MAN = /usr/man/manl/less.l
# OPTIM is passed to the compiler and the loader.
# It is normally "-O" but may be, for example, "-g".
OPTIM = -O
##########################################################################
# Files
##########################################################################
SRC1 = main.c option.c prim.c
SRC2 = ch.c position.c input.c output.c screen.c \
prompt.c line.c signal.c help.c ttyin.c command.c version.c
SRC = $(SRC1) $(SRC2)
OBJ = main.o option.o prim.o ch.o position.o input.o output.o screen.o \
prompt.o line.o signal.o help.o ttyin.o command.o version.o
##########################################################################
# Rules
##########################################################################
DEFS = "-DTERMIO=$(TERMIO)" \
"-DSIGSETMASK=$(SIGSETMASK)" \
"-Doff_t=$(off_t)" "-DVOID=$(VOID)" \
"-DREGCMP=$(REGCMP)" "-DRECOMP=$(RECOMP)" \
"-DSHELL_ESCAPE=$(SHELL_ESCAPE)" \
"-DEDITOR=$(EDITOR)" "-DEDIT_PGM=\"$(EDIT_PGM)\"" \
"-DONLY_RETURN=$(ONLY_RETURN)" \
"-DXENIX=$(XENIX)" \
"-DOLD_PAGER_NEW_LOCATION=\"$(OLD_PAGER_NEW_LOCATION)\""
CFLAGS = $(OPTIM) $(DEFS)
all: less
less: $(OBJ)
cc $(OPTIM) -o less $(OBJ) $(LIBS)
install: install_man install_less
install_man: less.l
for f in $(INSTALL_MAN); do rm -f $$f; cp less.l $$f; done
touch install_man
install_less: less
for f in $(INSTALL_LESS); do rm -f $$f; cp less $$f; done
touch install_less
pager_patch: pager_patch.c
cc $(CFLAGS) -s -o pager_patch pager_patch.c
install_pager_patch: pager_patch
if [ -s $(OLD_PAGER) -a ! -s $(OLD_PAGER_NEW_LOCATION) ]; then \
mv $(OLD_PAGER) $(OLD_PAGER_NEW_LOCATION); \
cp pager_patch $(OLD_PAGER); \
fi
touch install_pager_patch
$(OBJ): less.h funcs.h
lint:
lint -hp $(DEFS) $(SRC)
newfuncs:
mv funcs.h funcs.h.OLD
awk -f mkfuncs.awk $(SRC) >funcs.h
clean:
rm -f $(OBJ) less pager_patch
clobber:
rm -f *.o less pager_patch install_less install_man install_pager_patch
shar:
shar -v INSTALLATION less.l makefile.* *.h *.awk $(SRC1) > less.shar.a
shar -v $(SRC2) pager_patch.c > less.shar.b
SHAR_EOF
fi
if test -f 'makefile.xen'
then
echo shar: "will not over-write existing file 'makefile.xen'"
else
cat << \SHAR_EOF > 'makefile.xen'
# Makefile for "less"
#
# Invoked as:
# make all
# or make install
# Plain "make" is equivalent to "make all".
#
# If you add or delete functions, remake funcs.h by doing:
# make newfuncs
# This depends on the coding convention of function headers looking like:
# " \t public <function-type> \n <function-name> ( ... ) "
#
# Also provided:
# make lint # Runs "lint" on all the sources.
# make clean # Removes "less" and the .o files.
# make clobber # Pretty much the same as make "clean".
#
# make pager_patch # makes PAGER environment variable
# make install_pager_patch # catcher and installs it (see below)
##########################################################################
# System-specific parameters
##########################################################################
# Define XENIX if running under XENIX 3.0
XENIX = 1
# VOID is 1 if your C compiler supports the "void" type,
# 0 if it does not.
VOID = 1
# off_t is the type which lseek() returns.
# It is also the type of lseek()'s second argument.
off_t = long
# TERMIO is 1 if your system has /usr/include/termio.h.
# This is normally the case for System 5.
# If TERMIO is 0 your system must have /usr/include/sgtty.h.
# This is normally the case for BSD.
TERMIO = 1
# SIGSETMASK is 1 if your system has the sigsetmask() call.
# This is normally the case only for BSD 4.2,
# not for BSD 4.1 or System 5.
SIGSETMASK = 0
##########################################################################
# Optional and semi-optional features
##########################################################################
# REGCMP is 1 if your system has the regcmp() function.
# This is normally the case for System 5.
# RECOMP is 1 if your system has the re_comp() function.
# This is normally the case for BSD.
# If neither is 1, pattern matching is supported, but without metacharacters.
REGCMP = 1
RECOMP = 0
# SHELL_ESCAPE is 1 if you wish to allow shell escapes.
# (This is possible only if your system supplies the system() function.)
SHELL_ESCAPE = 0
# EDITOR is 1 if you wish to allow editor invocation (the "v" command).
# (This is possible only if your system supplies the system() function.)
# EDIT_PGM is the name of the (default) editor to be invoked.
EDITOR = 0
EDIT_PGM = /usr/ucb/vi
# parameters to "make install_pager_patch". OLD_PAGER will be moved to
# OLD_PAGER_NEW_LOCATION and pager_patch (in this directory) will be installed
# as OLD_PAGER. This patch will allow you to set the environment variable
# PAGER to specify your personal pager preference (is this a security hole?)
OLD_PAGER = /usr/ucb/more
OLD_PAGER_NEW_LOCATION = /usr/ucb/More
# ONLY_RETURN is 1 if you want RETURN to be the only input which
# will continue past an error message.
# Otherwise, any key will continue past an error message.
ONLY_RETURN = 0
##########################################################################
# Compilation environment.
##########################################################################
# LIBS is the list of libraries needed.
LIBS = -lcurses -ltermlib
# INSTALL_LESS is a list of the public versions of less.
# INSTALL_MAN is a list of the public versions of the manual page.
INSTALL_LESS = /usr/lbin/less
INSTALL_MAN = /usr/man/manl/less.l
# OPTIM is passed to the compiler and the loader.
# It is normally "-O" but may be, for example, "-g".
OPTIM = -O
##########################################################################
# Files
##########################################################################
SRC1 = main.c option.c prim.c
SRC2 = ch.c position.c input.c output.c screen.c \
prompt.c line.c signal.c help.c ttyin.c command.c version.c
SRC = $(SRC1) $(SRC2)
OBJ = main.o option.o prim.o ch.o position.o input.o output.o screen.o \
prompt.o line.o signal.o help.o ttyin.o command.o version.o
##########################################################################
# Rules
##########################################################################
DEFS = "-DTERMIO=$(TERMIO)" \
"-DSIGSETMASK=$(SIGSETMASK)" \
"-Doff_t=$(off_t)" "-DVOID=$(VOID)" \
"-DREGCMP=$(REGCMP)" "-DRECOMP=$(RECOMP)" \
"-DSHELL_ESCAPE=$(SHELL_ESCAPE)" \
"-DEDITOR=$(EDITOR)" "-DEDIT_PGM=\"$(EDIT_PGM)\"" \
"-DONLY_RETURN=$(ONLY_RETURN)" \
"-DXENIX=$(XENIX)" \
"-DOLD_PAGER_NEW_LOCATION=\"$(OLD_PAGER_NEW_LOCATION)\""
CFLAGS = $(OPTIM) $(DEFS)
all: less
less: $(OBJ)
cc $(OPTIM) -o less $(OBJ) $(LIBS)
install: install_man install_less
install_man: less.l
for f in $(INSTALL_MAN); do rm -f $$f; cp less.l $$f; done
touch install_man
install_less: less
for f in $(INSTALL_LESS); do rm -f $$f; cp less $$f; done
touch install_less
pager_patch: pager_patch.c
cc $(CFLAGS) -s -o pager_patch pager_patch.c
install_pager_patch: pager_patch
if [ -s $(OLD_PAGER) -a ! -s $(OLD_PAGER_NEW_LOCATION) ]; then \
mv $(OLD_PAGER) $(OLD_PAGER_NEW_LOCATION); \
cp pager_patch $(OLD_PAGER); \
fi
touch install_pager_patch
$(OBJ): less.h funcs.h
lint:
lint -hp $(DEFS) $(SRC)
newfuncs:
mv funcs.h funcs.h.OLD
awk -f mkfuncs.awk $(SRC) >funcs.h
clean:
rm -f $(OBJ) less pager_patch
clobber:
rm -f *.o less pager_patch install_less install_man install_pager_patch
shar:
shar -v INSTALLATION less.l makefile.* *.h *.awk $(SRC1) > less.shar.a
shar -v $(SRC2) pager_patch.c > less.shar.b
SHAR_EOF
fi
if test -f 'mkfuncs.awk'
then
echo shar: "will not over-write existing file 'mkfuncs.awk'"
else
cat << \SHAR_EOF > 'mkfuncs.awk'
BEGIN { FS="("; state = 0 }
/^ public/ { ftype = $0; state = 1 }
{ if (state == 1)
state = 2
else if (state == 2)
{ print ftype,$1,"();"; state = 0 }
}
SHAR_EOF
fi
if test -f 'n10-diff'
then
echo shar: "will not over-write existing file 'n10-diff'"
else
cat << \SHAR_EOF > 'n10-diff'
*** n10-old.c Sun May 4 01:45:06 1986
--- n10.c Mon Jul 14 12:27:54 1986
***************
*** 137,151
if(*codep && (esc || lead))move();
esct += w;
if(i&074000)xfont = (i>>9) & 03;
! if(*t.bdon & 0377){
! if(!bdmode && (xfont == 2)){
! oputs(t.bdon);
! bdmode++;
! }
! if(bdmode && (xfont != 2)){
! oputs(t.bdoff);
! bdmode = 0;
! }
}
if(xfont == ulfont){
for(k=w/t.Char;k>0;k--)oput('_');
--- 137,145 -----
if(*codep && (esc || lead))move();
esct += w;
if(i&074000)xfont = (i>>9) & 03;
! if(!bdmode && (xfont == 2)){
! if(*t.bdon & 0377)oputs(t.bdon);
! bdmode++;
}
if(bdmode && (xfont != 2)){
if(*t.bdoff & 0377)oputs(t.bdoff);
***************
*** 147,152
bdmode = 0;
}
}
if(xfont == ulfont){
for(k=w/t.Char;k>0;k--)oput('_');
for(k=w/t.Char;k>0;k--)oput('\b');
--- 141,150 -----
if(*t.bdon & 0377)oputs(t.bdon);
bdmode++;
}
+ if(bdmode && (xfont != 2)){
+ if(*t.bdoff & 0377)oputs(t.bdoff);
+ bdmode = 0;
+ }
if(xfont == ulfont){
for(k=w/t.Char;k>0;k--)oput('_');
for(k=w/t.Char;k>0;k--)oput('\b');
***************
*** 158,163
oput(' ');
}else{
if(plotmode)oputs(t.plotoff);
*obufp++ = *codep++;
if(obufp == (obuf + OBUFSZ + ascii - 1))flusho();
/* oput(*codep++);*/
--- 156,162 -----
oput(' ');
}else{
if(plotmode)oputs(t.plotoff);
+ if(obufp >= (obuf + OBUFSZ + ascii - 1 - (bdmode?3:1)))flusho();
*obufp++ = *codep++;
if(bdmode && !*t.bdon){
*obufp++ = '\b';
***************
*** 159,165
}else{
if(plotmode)oputs(t.plotoff);
*obufp++ = *codep++;
! if(obufp == (obuf + OBUFSZ + ascii - 1))flusho();
/* oput(*codep++);*/
}
}
--- 158,167 -----
if(plotmode)oputs(t.plotoff);
if(obufp >= (obuf + OBUFSZ + ascii - 1 - (bdmode?3:1)))flusho();
*obufp++ = *codep++;
! if(bdmode && !*t.bdon){
! *obufp++ = '\b';
! *obufp++ = codep[-1];
! }
/* oput(*codep++);*/
}
}
SHAR_EOF
fi
if test -f 'option.c'
then
echo shar: "will not over-write existing file 'option.c'"
else
cat << \SHAR_EOF > 'option.c'
/*
* Process command line options.
* Each option is a single letter which controls a program variable.
* The options have defaults which may be changed via
* the command line option, or toggled via the "-" command.
*/
#include "less.h"
#define toupper(c) ((c)-'a'+'A')
/*
* Types of options.
*/
#define BOOL 01 /* Boolean option: 0 or 1 */
#define TRIPLE 02 /* Triple-valued option: 0, 1 or 2 */
#define NUMBER 04 /* Numeric option */
#define NO_TOGGLE 0100 /* Option cannot be toggled with "-" cmd */
/*
* Variables controlled by command line options.
*/
public int p_nbufs, f_nbufs; /* Number of buffers. There are two values,
one used for input from a pipe and
the other for input from a file. */
public int clean_data; /* Can we assume the data is "clean"?
(That is, free of nulls, etc) */
public int quiet; /* Should we suppress the audible bell? */
public int top_search; /* Should forward searches start at the top
of the screen? (alternative is bottom) */
public int top_scroll; /* Repaint screen from top?
(alternative is scroll from bottom) */
public int pr_type; /* Type of prompt (short, medium, long) */
public int bs_mode; /* How to process backspaces */
public int know_dumb; /* Don't complain about dumb terminals */
public int quit_at_eof; /* Quit after hitting end of file twice */
public int squeeze; /* Squeeze multiple blank lines into one */
public int tabstop; /* Tab settings */
public int back_scroll; /* Repaint screen on backwards movement */
public int twiddle; /* Display "~" for lines after EOF */
extern int nbufs;
extern int sc_window;
extern char *first_cmd;
extern char *every_first_cmd;
#define DEF_F_NBUFS 5 /* Default for f_nbufs */
#define DEF_P_NBUFS 12 /* Default for p_nbufs */
static struct option
{
char oletter; /* The controlling letter (a-z) */
char otype; /* Type of the option */
int odefault; /* Default value */
int *ovar; /* Pointer to the associated variable */
char *odesc[3]; /* Description of each value */
} option[] =
{
{ 'c', BOOL, 0, &clean_data,
{ "Don't assume data is clean",
"Assume data is clean",
NULL
}
},
{ 'd', BOOL|NO_TOGGLE, 0, &know_dumb,
{ NULL, NULL, NULL}
},
{ 'e', BOOL, 0, &quit_at_eof,
{ "Don't quit at end-of-file",
"Quit at end-of-file",
NULL
}
},
{ 'h', NUMBER, -1, &back_scroll,
{ "Backwards scroll limit is %d lines",
NULL, NULL
}
},
{ 'p', BOOL, 0, &top_scroll,
{ "Repaint by scrolling from bottom of screen",
"Repaint by painting from top of screen",
NULL
}
},
{ 'x', NUMBER, 8, &tabstop,
{ "Tab stops every %d spaces",
NULL, NULL
}
},
{ 's', BOOL, 0, &squeeze,
{ "Don't squeeze multiple blank lines",
"Squeeze multiple blank lines",
NULL
}
},
{ 't', BOOL, 1, &top_search,
{ "Forward search starts from bottom of screen",
"Forward search starts from top of screen",
NULL
}
},
{ 'w', BOOL, 1, &twiddle,
{ "Display nothing for lines after end-of-file",
"Display ~ for lines after end-of-file",
NULL
}
},
{ 'm', TRIPLE, 0, &pr_type,
{ "Prompt with a colon",
"Prompt with a message",
"Prompt with a verbose message"
}
},
{ 'q', TRIPLE, 0, &quiet,
{ "Ring the bell for errors AND at eof/bof",
"Ring the bell for errors but not at eof/bof",
"Never ring the bell"
}
},
{ 'u', TRIPLE, 0, &bs_mode,
{ "Underlined text displayed in underline mode",
"All backspaces cause overstrike",
"Backspaces print as ^H"
}
},
{ 'z', NUMBER, 24, &sc_window,
{ "Scroll window size is %d lines",
NULL, NULL
}
},
{ '\0' }
};
public char all_options[64]; /* List of all valid options */
/*
* Initialize each option to its default value.
*/
public void
init_option()
{
register struct option *o;
register char *p;
/*
* First do special cases, not in option table.
*/
first_cmd = every_first_cmd = NULL;
f_nbufs = DEF_F_NBUFS; /* -bf */
p_nbufs = DEF_P_NBUFS; /* -bp */
p = all_options;
*p++ = 'b';
for (o = option; o->oletter != '\0'; o++)
{
/*
* Set each variable to its default.
* Also make a list of all options, in "all_options".
*/
*(o->ovar) = o->odefault;
*p++ = o->oletter;
if (o->otype & TRIPLE)
*p++ = toupper(o->oletter);
}
*p = '\0';
}
/*
* Toggle command line flags from within the program.
* Used by the "-" command.
*/
public void
toggle_option(c)
int c;
{
register struct option *o;
char message[100];
char buf[5];
/*
* First check for special cases not handled by the option table.
*/
switch (c)
{
case 'b':
sprintf(message, "%d buffers", nbufs);
error(message);
return;
}
for (o = option; o->oletter != '\0'; o++)
{
if ((o->otype & BOOL) && (o->oletter == c) &&
(o->otype & NO_TOGGLE) == 0)
{
/*
* Boolean option:
* just toggle it.
*/
*(o->ovar) = ! *(o->ovar);
error(o->odesc[*(o->ovar)]);
return;
} else if ((o->otype & TRIPLE) && (o->oletter == c) &&
(o->otype & NO_TOGGLE) == 0)
{
/*
* Triple-valued option with lower case letter:
* make it 1 unless already 1, then make it 0.
*/
*(o->ovar) = (*(o->ovar) == 1) ? 0 : 1;
error(o->odesc[*(o->ovar)]);
return;
} else if ((o->otype & TRIPLE) && (toupper(o->oletter) == c) &&
(o->otype & NO_TOGGLE) == 0)
{
/*
* Triple-valued option with upper case letter:
* make it 2 unless already 2, then make it 0.
*/
*(o->ovar) = (*(o->ovar) == 2) ? 0 : 2;
error(o->odesc[*(o->ovar)]);
return;
} else if ((o->otype & NUMBER) && (o->oletter == c) &&
(o->otype & NO_TOGGLE) == 0)
{
sprintf(message, o->odesc[0], *(o->ovar));
error(message);
return;
}
}
if (control_char(c))
sprintf(buf, "^%c", carat_char(c));
else
sprintf(buf, "%c", c);
sprintf(message, "\"-%s\": no such flag. Use one of \"%s\"",
buf, all_options);
error(message);
}
/*
* Scan an argument (either from command line or from LESS environment
* variable) and process it.
*/
public void
scan_option(s)
char *s;
{
register struct option *o;
register int c;
if (s == NULL)
return;
next:
if (*s == '\0')
return;
switch (c = *s++)
{
case '-':
case ' ':
case '\t':
goto next;
case '+':
if (*s == '+')
every_first_cmd = ++s;
first_cmd = s;
return;
case 'b':
switch (*s)
{
case 'f':
s++;
f_nbufs = getnum(&s, 'b');
break;
case 'p':
s++;
p_nbufs = getnum(&s, 'b');
break;
default:
f_nbufs = p_nbufs = getnum(&s, 'b');
break;
}
goto next;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
/*
* Handle special "more" compatibility form "-number"
* to set the scrolling window size.
*/
s--;
sc_window = getnum(&s, '-');
goto next;
}
}
for (o = option; o->oletter != '\0'; o++)
{
if ((o->otype & BOOL) && (o->oletter == c))
{
*(o->ovar) = ! o->odefault;
goto next;
} else if ((o->otype & TRIPLE) && (o->oletter == c))
{
*(o->ovar) = (o->odefault == 1) ? 0 : 1;
goto next;
} else if ((o->otype & TRIPLE) && (toupper(o->oletter) == c))
{
*(o->ovar) = (o->odefault == 2) ? 0 : 2;
goto next;
} else if ((o->otype & NUMBER) && (o->oletter == c))
{
*(o->ovar) = getnum(&s, c);
goto next;
}
}
printf("\"-%c\": invalid flag\n", c);
exit(1);
}
/*
* Translate a string into a number.
* Like atoi(), but takes a pointer to a char *, and updates
* the char * to point after the translated number.
*/
static int
getnum(sp, c)
char **sp;
int c;
{
register char *s;
register int n;
s = *sp;
if (*s < '0' || *s > '9')
{
printf("number is required after -%c\n", c);
exit(1);
}
n = 0;
while (*s >= '0' && *s <= '9')
n = 10 * n + *s++ - '0';
*sp = s;
return (n);
}
SHAR_EOF
fi
if test -f 'output.c'
then
echo shar: "will not over-write existing file 'output.c'"
else
cat << \SHAR_EOF > 'output.c'
/*
* High level routines dealing with the output to the screen.
*/
#include "less.h"
extern int sigs;
extern int sc_width, sc_height;
extern int bo_width, be_width;
extern int ul_width, ue_width;
extern int so_width, se_width;
extern int tabstop;
extern int twiddle;
extern char *line;
extern char *first_cmd;
/*
* Display the line which is in the line buffer.
*/
public void
put_line()
{
register char *p;
register int c;
register int column;
extern int auto_wrap, ignaw;
if (sigs)
/*
* Don't output if a signal is pending.
*/
return;
if (line == NULL)
line = (twiddle) ? "~" : "";
column = 0;
for (p = line; *p != '\0'; p++)
{
switch (c = *p)
{
case UL_CHAR:
ul_enter();
column += ul_width;
break;
case UE_CHAR:
ul_exit();
column += ue_width;
break;
case BO_CHAR:
bo_enter();
column += bo_width;
break;
case BE_CHAR:
bo_exit();
column += be_width;
break;
case '\t':
do
{
putc(' ');
column++;
} while ((column % tabstop) != 0);
break;
case '\b':
putbs();
column--;
break;
default:
if (c & 0200)
{
putc('^');
putc(c & 0177);
column += 2;
} else
{
putc(c);
column++;
}
}
}
if (column < sc_width || !auto_wrap || ignaw)
putc('\n');
}
/*
* Is a given character a "control" character?
* {{ ASCII DEPENDENT }}
*/
public int
control_char(c)
int c;
{
return (c < ' ' || c == '\177');
}
/*
* Return the printable character used to identify a control character
* (printed after a carat; e.g. '\3' => "^C").
* {{ ASCII DEPENDENT }}
*/
public int
carat_char(c)
int c;
{
return ((c == '\177') ? '?' : (c | 0100));
}
static char obuf[1024];
static char *ob = obuf;
/*
* Flush buffered output.
*/
public void
flush()
{
write(1, obuf, ob-obuf);
ob = obuf;
}
/*
* Discard buffered output.
*/
public void
dropout()
{
ob = obuf;
}
/*
* Output a character.
*/
public void
putc(c)
int c;
{
if (ob >= &obuf[sizeof(obuf)])
flush();
*ob++ = c;
}
/*
* Output a string.
*/
public void
puts(s)
register char *s;
{
while (*s != '\0')
putc(*s++);
}
/*
* Output a message in the lower left corner of the screen
* and wait for carriage return.
*/
static char return_to_continue[] = " (press RETURN)";
public void
error(s)
char *s;
{
register int c;
static char buf[2];
lower_left();
clear_eol();
so_enter();
puts(s);
puts(return_to_continue);
so_exit();
#if ONLY_RETURN
while ((c = getc()) != '\n' && c != '\r')
bell();
#else
c = getc();
if (c != '\n' && c != '\r' && c != ' ')
{
buf[0] = c;
first_cmd = buf;
}
#endif
if (strlen(s) > sc_width)
repaint();
}
public int
error_width()
{
/*
* Don't use the last position, because some terminals
* will scroll if you write in the last char of the last line.
*/
return (sc_width -
(sizeof(return_to_continue) + so_width + se_width + 1));
}
SHAR_EOF
fi
if test -f 'pager_patch.c'
then
echo shar: "will not over-write existing file 'pager_patch.c'"
else
cat << \SHAR_EOF > 'pager_patch.c'
/*
* Special interface that checks for the environment variable PAGER. If
* present, the program specified is executed, otherwise OLD_PAGER_NEW_LOCATION
* (specified below). This program should replace /usr/ucb/more (or whatever
* your default pager is) and more should be moved to OLD_PAGER_NEW_LOCATION.
* This is essentially a fix for all the programs which *should* check for the
* environment variable PAGER, but don't - hopefully it will be obsoleted as
* old programs are update to check for PAGER so we can loose the overhead of
* reexecuting even this small program ...
*
* Casey Leedom (lll-crg.arpa!csustan!casey) - 5/29/86
*/
#ifndef OLD_PAGER_NEW_LOCATION
# define OLD_PAGER_NEW_LOCATION "/usr/ucb/More"
#endif !OLD_PAGER_NEW_LOCATION
void
main(argc, argv)
int argc;
char **argv;
{
char *pager, *getenv();
if (!(pager = getenv("PAGER")))
pager = OLD_PAGER_NEW_LOCATION;
(void) execv(pager, argv);
}
SHAR_EOF
fi
if test -f 'position.c'
then
echo shar: "will not over-write existing file 'position.c'"
else
cat << \SHAR_EOF > 'position.c'
/*
* Routines dealing with the "position" table.
* This is a table which tells the position (in the input file) of the
* first char on each currently displayed line.
*
* {{ The position table is scrolled by moving all the entries.
* Would be better to have a circular table
* and just change a couple of pointers. }}
*/
#include "less.h"
#include "position.h"
#define NPOS 100 /* {{ sc_height must be less than NPOS }} */
static POSITION table[NPOS]; /* The position table */
extern int sc_width, sc_height;
/*
* Return the position of one of:
* the top (first) line on the screen
* the second line on the screen
* the bottom line on the screen
* the line after the bottom line on the screen
*/
public POSITION
position(where)
int where;
{
switch (where)
{
case BOTTOM:
where = sc_height - 2;
break;
case BOTTOM_PLUS_ONE:
where = sc_height - 1;
break;
}
return (table[where]);
}
/*
* Add a new file position to the bottom of the position table.
*/
public void
add_forw_pos(pos)
POSITION pos;
{
register int i;
/*
* Scroll the position table up.
*/
for (i = 1; i < sc_height; i++)
table[i-1] = table[i];
table[sc_height - 1] = pos;
}
/*
* Add a new file position to the top of the position table.
*/
public void
add_back_pos(pos)
POSITION pos;
{
register int i;
/*
* Scroll the position table down.
*/
for (i = sc_height - 1; i > 0; i--)
table[i] = table[i-1];
table[0] = pos;
}
/*
* Initialize the position table, done whenever we clear the screen.
*/
public void
pos_clear()
{
register int i;
for (i = 0; i < sc_height; i++)
table[i] = NULL_POSITION;
}
/*
* See if the byte at a specified position is currently on the screen.
* Check the position table to see if the position falls within its range.
* Return the position table entry if found, -1 if not.
*/
public int
onscreen(pos)
POSITION pos;
{
register int i;
if (pos < table[0])
return (-1);
for (i = 1; i < sc_height; i++)
if (pos < table[i])
return (i-1);
return (-1);
}
SHAR_EOF
fi
if test -f 'position.h'
then
echo shar: "will not over-write existing file 'position.h'"
else
cat << \SHAR_EOF > 'position.h'
/*
* Include file for interfacing to position.c modules.
*/
#define TOP 0
#define TOP_PLUS_ONE 1
#define BOTTOM -1
#define BOTTOM_PLUS_ONE -2
SHAR_EOF
fi
if test -f 'prim.c'
then
echo shar: "will not over-write existing file 'prim.c'"
else
cat << \SHAR_EOF > 'prim.c'
/*
* Primitives for displaying the file on the screen.
*/
#include "less.h"
#include "position.h"
public int hit_eof; /* Keeps track of how many times we hit end of file */
extern int quiet;
extern int top_search;
extern int top_scroll;
extern int back_scroll;
extern int sc_width, sc_height;
extern int sigs;
extern char *line;
extern char *first_cmd;
/*
* Sound the bell to indicate he is trying to move past end of file.
*/
static void
eof_bell()
{
if (quiet == NOT_QUIET)
bell();
else
vbell();
}
/*
* Check to see if the end of file is currently "displayed".
*/
static void
eof_check()
{
POSITION pos;
/*
* If the bottom line is empty, we are at EOF.
* If the bottom line ends at the file length,
* we must be just at EOF.
*/
pos = position(BOTTOM_PLUS_ONE);
if (pos == NULL_POSITION || pos == ch_length())
hit_eof++;
}
/*
* Display n lines, scrolling forward,
* starting at position pos in the input file.
* "force" means display the n lines even if we hit end of file.
* "only_last" means display only the last screenful if n > screen size.
*/
static void
forw(n, pos, force, only_last)
register int n;
POSITION pos;
int force;
int only_last;
{
int eof = 0;
int nlines = 0;
int repaint_flag;
/*
* repaint_flag tells us not to display anything till the end,
* then just repaint the entire screen.
*/
repaint_flag = (only_last && n > sc_height-1);
if (!repaint_flag)
{
if (top_scroll && n >= sc_height - 1)
{
/*
* Start a new screen.
* {{ This is not really desirable if we happen
* to hit eof in the middle of this screen,
* but we don't know if that will happen now. }}
*/
clear();
home();
force = 1;
} else
{
lower_left();
clear_eol();
}
if (pos != position(BOTTOM_PLUS_ONE))
{
/*
* This is not contiguous with what is
* currently displayed. Clear the screen image
* (position table) and start a new screen.
*/
pos_clear();
add_forw_pos(pos);
force = 1;
if (top_scroll)
{
clear();
home();
} else
{
puts("...skipping...\n");
}
}
}
while (--n >= 0)
{
/*
* Read the next line of input.
*/
pos = forw_line(pos);
if (pos == NULL_POSITION)
{
/*
* End of file: stop here unless the top line
* is still empty, or "force" is true.
*/
eof = 1;
if (!force && position(TOP) != NULL_POSITION)
break;
line = NULL;
}
/*
* Add the position of the next line to the position table.
* Display the current line on the screen.
*/
add_forw_pos(pos);
nlines++;
if (!repaint_flag)
put_line();
}
if (eof)
hit_eof++;
else
eof_check();
if (nlines == 0)
eof_bell();
else if (repaint_flag)
repaint();
}
/*
* Display n lines, scrolling backward.
*/
static void
back(n, pos, force, only_last)
register int n;
POSITION pos;
int force;
int only_last;
{
int nlines = 0;
int repaint_flag;
repaint_flag = (n > back_scroll || (only_last && n > sc_height-1));
hit_eof = 0;
while (--n >= 0)
{
/*
* Get the previous line of input.
*/
pos = back_line(pos);
if (pos == NULL_POSITION)
{
/*
* Beginning of file: stop here unless "force" is true.
*/
if (!force)
break;
line = NULL;
}
/*
* Add the position of the previous line to the position table.
* Display the line on the screen.
*/
add_back_pos(pos);
nlines++;
if (!repaint_flag)
{
home();
add_line();
put_line();
}
}
eof_check();
if (nlines == 0)
eof_bell();
else if (repaint_flag)
repaint();
}
/*
* Display n more lines, forward.
* Start just after the line currently displayed at the bottom of the screen.
*/
public void
forward(n, only_last)
int n;
int only_last;
{
POSITION pos;
pos = position(BOTTOM_PLUS_ONE);
if (pos == NULL_POSITION)
{
eof_bell();
hit_eof++;
return;
}
forw(n, pos, 0, only_last);
}
/*
* Display n more lines, backward.
* Start just before the line currently displayed at the top of the screen.
*/
public void
backward(n, only_last)
int n;
int only_last;
{
POSITION pos;
pos = position(TOP);
if (pos == NULL_POSITION)
{
/*
* This will almost never happen,
* because the top line is almost never empty.
*/
eof_bell();
return;
}
back(n, pos, 0, only_last);
}
/*
* Repaint the screen, starting from a specified position.
*/
static void
prepaint(pos)
POSITION pos;
{
hit_eof = 0;
forw(sc_height-1, pos, 0, 0);
}
/*
* Repaint the screen.
*/
public void
repaint()
{
/*
* Start at the line currently at the top of the screen
* and redisplay the screen.
*/
prepaint(position(TOP));
}
/*
* Jump to the end of the file.
* It is more convenient to paint the screen backward,
* from the end of the file toward the beginning.
*/
public void
jump_forw()
{
POSITION pos;
if (ch_end_seek())
{
error("Cannot seek to end of file");
return;
}
pos = ch_tell();
clear();
pos_clear();
add_back_pos(pos);
back(sc_height - 1, pos, 0, 0);
}
/*
* Jump to line n in the file.
*/
public void
jump_back(n)
register int n;
{
register int c;
/*
* This is done the slow way, by starting at the beginning
* of the file and counting newlines.
*/
if (ch_seek((POSITION)0))
{
/*
* Probably a pipe with beginning of file no longer buffered.
*/
error("Cannot get to beginning of file");
return;
}
/*
* Start counting lines.
*/
while (--n > 0)
{
while ((c = ch_forw_get()) != '\n')
if (c == EOF)
{
error("File is not that long");
/* {{ Maybe tell him how long it is? }} */
return;
}
}
/*
* Finally found the place to start.
* Clear and redisplay the screen from there.
*
* {{ We *could* figure out if the new position is
* close enough to just scroll there without clearing
* the screen, but it's not worth it. }}
*/
prepaint(ch_tell());
}
/*
* Jump to a specified percentage into the file.
* This is a poor compensation for not being able to
* quickly jump to a specific line number.
*/
public void
jump_percent(percent)
int percent;
{
POSITION pos, len;
/*
* Determine the position in the file
* (the specified percentage of the file's length).
*/
if ((len = ch_length()) == NULL_POSITION)
{
error("Don't know length of file");
return;
}
pos = (percent * len) / 100;
jump_loc(pos);
}
public void
jump_loc(pos)
POSITION pos;
{
register int c;
register int nline;
POSITION tpos;
/*
* See if the desired line is BEFORE the currently
* displayed screen. If so, see if it is close enough
* to scroll backwards to it.
*/
tpos = position(TOP);
if (pos < tpos)
{
for (nline = 1; nline <= back_scroll; nline++)
{
tpos = back_line(tpos);
if (tpos == NULL_POSITION || tpos <= pos)
{
back(nline, position(TOP), 1, 0);
return;
}
}
} else if ((nline = onscreen(pos)) >= 0)
{
/*
* The line is currently displayed.
* Just scroll there.
*/
forw(nline, position(BOTTOM_PLUS_ONE), 1, 0);
return;
}
/*
* Line is not on screen.
* Back up to the beginning of the current line.
*/
if (ch_seek(pos))
{
error("Cannot seek to that position");
return;
}
while ((c = ch_back_get()) != '\n' && c != EOF)
;
if (c == '\n')
(void) ch_forw_get();
/*
* Clear and paint the screen.
*/
prepaint(ch_tell());
}
/*
* The table of marks.
* A mark is simply a position in the file.
*/
static POSITION marks[26];
/*
* Initialize the mark table to show no marks are set.
*/
public void
init_mark()
{
int i;
for (i = 0; i < 26; i++)
marks[i] = NULL_POSITION;
}
/*
* See if a mark letter is valid (between a and z).
*/
static int
badmark(c)
int c;
{
if (c < 'a' || c > 'z')
{
error("Choose a letter between 'a' and 'z'");
return (1);
}
return (0);
}
/*
* Set a mark.
*/
public void
setmark(c)
int c;
{
if (badmark(c))
return;
marks[c-'a'] = position(TOP);
}
/*
* Go to a previously set mark.
*/
public void
gomark(c)
int c;
{
POSITION pos;
if (badmark(c))
return;
if ((pos = marks[c-'a']) == NULL_POSITION)
error("mark not set");
else
jump_loc(pos);
}
/*
* Search for the n-th occurence of a specified pattern,
* either forward (direction == '/'), or backwards (direction == '?').
*/
public void
search(direction, pattern, n)
int direction;
char *pattern;
register int n;
{
register int search_forward = (direction == '/');
POSITION pos, linepos;
#if RECOMP
char *re_comp();
char *errmsg;
/*
* (re_comp handles a null pattern internally,
* so there is no need to check for a null pattern here.)
*/
if ((errmsg = re_comp(pattern)) != NULL)
{
error(errmsg);
return;
}
#else
#if REGCMP
char *regcmp();
static char *cpattern = NULL;
if (pattern == NULL || *pattern == '\0')
{
/*
* A null pattern means use the previous pattern.
* The compiled previous pattern is in cpattern, so just use it.
*/
if (cpattern == NULL)
{
error("No previous regular expression");
return;
}
} else
{
/*
* Otherwise compile the given pattern.
*/
char *s;
if ((s = regcmp(pattern, 0)) == NULL)
{
error("Invalid pattern");
return;
}
if (cpattern != NULL)
free(cpattern);
cpattern = s;
}
#else
static char lpbuf[100];
static char *last_pattern = NULL;
if (pattern == NULL || *pattern == '\0')
{
/*
* Null pattern means use the previous pattern.
*/
if (last_pattern == NULL)
{
error("No previous regular expression");
return;
}
pattern = last_pattern;
} else
{
strcpy(lpbuf, pattern);
last_pattern = lpbuf;
}
#endif
#endif
/*
* Figure out where to start the search.
*/
if (position(TOP) == NULL_POSITION)
{
/*
* Nothing is currently displayed.
* Start at the beginning of the file.
* (This case is mainly for first_cmd searches,
* for example, "+/xyz" on the command line.)
*/
pos = (POSITION)0;
} else if (!search_forward)
{
/*
* Backward search: start just before the top line
* displayed on the screen.
*/
pos = position(TOP);
} else if (top_search)
{
/*
* Forward search and "start from top".
* Start at the second line displayed on the screen.
*/
pos = position(TOP_PLUS_ONE);
} else
{
/*
* Forward search but don't "start from top".
* Start just after the bottom line displayed on the screen.
*/
pos = position(BOTTOM_PLUS_ONE);
}
if (pos == NULL_POSITION)
{
/*
* Can't find anyplace to start searching from.
*/
error("Nothing to search");
return;
}
for (;;)
{
/*
* Get lines until we find a matching one or
* until we hit end-of-file (or beginning-of-file
* if we're going backwards).
*/
if (sigs)
/*
* A signal aborts the search.
*/
return;
if (search_forward)
{
/*
* Read the next line, and save the
* starting position of that line in linepos.
*/
linepos = pos;
pos = forw_raw_line(pos);
} else
{
/*
* Read the previous line and save the
* starting position of that line in linepos.
*/
pos = back_raw_line(pos);
linepos = pos;
}
if (pos == NULL_POSITION)
{
/*
* We hit EOF/BOF without a match.
*/
error("Pattern not found");
return;
}
/*
* Test the next line to see if we have a match.
* This is done in a variety of ways, depending
* on what pattern matching functions are available.
*/
#if REGCMP
if ( (regex(cpattern, line) != NULL)
#else
#if RECOMP
if ( (re_exec(line) == 1)
#else
if ( (match(pattern, line))
#endif
#endif
&& (--n <= 0) )
/*
* Found the matching line.
*/
break;
}
jump_loc(linepos);
}
#if (!REGCMP) && (!RECOMP)
/*
* We have neither regcmp() nor re_comp().
* We use this function to do simple pattern matching.
* It supports no metacharacters like *, etc.
*/
static int
match(pattern, buf)
char *pattern, *buf;
{
register char *pp, *lp;
for ( ; *buf != '\0'; buf++)
{
for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++)
if (*pp == '\0' || *lp == '\0')
break;
if (*pp == '\0')
return (1);
}
return (0);
}
#endif
SHAR_EOF
fi
if test -f 'prompt.c'
then
echo shar: "will not over-write existing file 'prompt.c'"
else
cat << \SHAR_EOF > 'prompt.c'
/*
* Prompting and other messages.
* There are three flavors of prompts, SHORT, MEDIUM and LONG,
* selected by the -m/-M options.
* A prompt is either a colon or a message composed of various
* pieces, such as the name of the file being viewed, the percentage
* into the file, etc.
*/
#include "less.h"
#include "position.h"
extern int pr_type;
extern int ispipe;
extern int hit_eof;
extern int new_file;
extern int sc_width;
extern char current_file[];
extern int ac;
extern char **av;
extern int curr_ac;
static char message[500];
/*
* Append the name of the current file (to the message buffer).
*/
static void
ap_filename()
{
if (!ispipe)
sprintf(message + strlen(message),
"%s", current_file);
}
/*
* Append the "file N of M" message.
*/
static void
ap_of()
{
if (ac > 1)
sprintf(message + strlen(message),
" (file %d of %d)", curr_ac+1, ac);
}
/*
* Append the byte offset into the current file.
*/
static void
ap_byte()
{
POSITION pos, len;
pos = position(BOTTOM_PLUS_ONE);
if (pos != NULL_POSITION)
{
sprintf(message + strlen(message),
" byte %ld", pos);
len = ch_length();
if (len > 0)
sprintf(message + strlen(message),
"/%ld", len);
}
}
/*
* Append the percentage into the current file.
* If we cannot find the percentage and must_print is true,
* the use the byte offset.
*/
static void
ap_percent(must_print)
{
POSITION pos,len;
pos = position(BOTTOM_PLUS_ONE);
len = ch_length();
if (len > 0 && pos != NULL_POSITION)
sprintf(message + strlen(message),
" (%ld%%)", (100 * pos) / len);
else if (must_print)
ap_byte();
}
/*
* Append the end-of-file message.
*/
static void
ap_eof()
{
strcat(message, " END");
if (curr_ac + 1 < ac)
sprintf(message + strlen(message),
" - Next: %s", av[curr_ac+1]);
}
/*
* Return a message suitable for printing by the "=" command.
*/
public char *
eq_message()
{
message[0] = '\0';
ap_filename();
ap_of();
ap_byte();
ap_percent(0);
/*
* Truncate to the screen width.
* {{ This isn't very nice. }}
*/
message[error_width()] = '\0';
return (message);
}
/*
* Return a prompt.
* This depends on the prompt type (SHORT, MEDIUM, LONG), etc.
* If we can't come up with an appropriate prompt, return NULL
* and the caller will prompt with a colon.
*/
public char *
pr_string()
{
message[0] = '\0';
switch (pr_type)
{
case PR_SHORT:
if (new_file)
{
ap_filename();
ap_of();
}
if (hit_eof)
ap_eof();
break;
case PR_MEDIUM:
if (new_file)
{
ap_filename();
ap_of();
}
if (hit_eof)
ap_eof();
else
ap_percent(1);
break;
case PR_LONG:
ap_filename();
if (new_file)
ap_of();
ap_byte();
if (hit_eof)
ap_eof();
else
ap_percent(0);
break;
}
new_file = 0;
if (message[0] == '\0')
return (NULL);
/*
* Truncate to the screen width.
* {{ This isn't very nice. }}
*/
message[sc_width-2] = '\0';
return (message);
}
SHAR_EOF
fi
if test -f 'screen.c'
then
echo shar: "will not over-write existing file 'screen.c'"
else
cat << \SHAR_EOF > 'screen.c'
/*
* Routines which deal with the characteristics of the terminal.
* Uses termcap to be as terminal-independent as possible.
*
* {{ Someday this should be rewritten to use curses. }}
*/
#include "less.h"
#if XENIX
#include <sys/types.h>
#include <sys/ioctl.h>
#endif
#if TERMIO
#include <termio.h>
#else
#include <sgtty.h>
#endif
/*
* Strings passed to tputs() to do various terminal functions.
*/
static char
*sc_pad, /* Pad string */
*sc_home, /* Cursor home */
*sc_addline, /* Add line, scroll down following lines */
*sc_lower_left, /* Cursor to last line, first column */
*sc_move, /* General cursor positioning */
*sc_clear, /* Clear screen */
*sc_eol_clear, /* Clear to end of line */
*sc_s_in, /* Enter standout (highlighted) mode */
*sc_s_out, /* Exit standout mode */
*sc_u_in, /* Enter underline mode */
*sc_u_out, /* Exit underline mode */
*sc_b_in, /* Enter bold mode */
*sc_b_out, /* Exit bold mode */
*sc_visual_bell, /* Visual bell (flash screen) sequence */
*sc_backspace, /* Backspace cursor */
*sc_init, /* Startup terminal initialization */
*sc_deinit; /* Exit terminal de-intialization */
static int dumb;
static int hard;
public int auto_wrap; /* Terminal does \r\n when write past margin */
public int ignaw; /* Terminal ignores \n immediately after wrap */
public int erase_char, kill_char; /* The user's erase and line-kill chars */
public int sc_width, sc_height; /* Height & width of screen */
public int sc_window = -1; /* window size for forward and backward */
public int bo_width, be_width; /* Printing width of boldface sequences */
public int ul_width, ue_width; /* Printing width of underline sequences */
public int so_width, se_width; /* Printing width of standout sequences */
/*
* These two variables are sometimes defined in,
* and needed by, the termcap library.
* It may be necessary on some systems to declare them extern here.
*/
/*extern*/ short ospeed; /* Terminal output baud rate */
/*extern*/ char P ; /* Pad character */
extern int quiet; /* If VERY_QUIET, use visual bell for bell */
extern int know_dumb; /* Don't complain about a dumb terminal */
extern int back_scroll;
char *tgetstr();
char *tgoto();
/*
* Change terminal to "raw mode", or restore to "normal" mode.
* "Raw mode" means
* 1. An outstanding read will complete on receipt of a single keystroke.
* 2. Input is not echoed.
* 3. On output, \n is mapped to \r\n.
* 4. \t is NOT be expanded into spaces.
* 5. Signal-causing characters such as ctrl-C (interrupt),
* etc. are NOT disabled.
* It doesn't matter whether an input \n is mapped to \r, or vice versa.
*/
public void
raw_mode(on)
int on;
{
#if TERMIO
struct termio s;
static struct termio save_term;
if (on)
{
/*
* Get terminal modes.
*/
ioctl(2, TCGETA, &s);
/*
* Save modes and set certain variables dependent on modes.
*/
save_term = s;
ospeed = s.c_cflag & CBAUD;
erase_char = s.c_cc[VERASE];
kill_char = s.c_cc[VKILL];
/*
* Set the modes to the way we want them.
*/
s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
s.c_oflag |= (OPOST|ONLCR|TAB3);
s.c_oflag &= ~(OCRNL|ONOCR|ONLRET);
s.c_cc[VMIN] = 1;
s.c_cc[VTIME] = 0;
} else
{
/*
* Restore saved modes.
*/
s = save_term;
}
ioctl(2, TCSETAW, &s);
#else
struct sgttyb s;
static struct sgttyb save_term;
if (on)
{
/*
* Get terminal modes.
*/
ioctl(2, TIOCGETP, &s);
/*
* Save modes and set certain variables dependent on modes.
*/
save_term = s;
ospeed = s.sg_ospeed;
erase_char = s.sg_erase;
kill_char = s.sg_kill;
/*
* Set the modes to the way we want them.
*/
s.sg_flags |= CBREAK;
s.sg_flags &= ~(ECHO|XTABS);
} else
{
/*
* Restore saved modes.
*/
s = save_term;
}
ioctl(2, TIOCSETN, &s);
#endif
}
static int couldnt = 0;
static void
cannot(s)
char *s;
{
if (know_dumb)
/*
* He knows he has a dumb terminal, so don't tell him.
*/
return;
printf("WARNING: terminal cannot \"%s\"\n", s);
couldnt = 1;
}
/*
* Get terminal capabilities via termcap.
*/
public void
get_term()
{
char termbuf[1024];
char *sp;
static char sbuf[150];
char *getenv();
/*
* Find out what kind of terminal this is.
*/
if (tgetent(termbuf, getenv("TERM")) <= 0)
dumb = 1;
/*
* Get size of the screen.
*/
if (dumb || (sc_height = tgetnum("li")) < 0 || tgetflag("hc"))
{
/* Oh no, this is a hardcopy terminal. */
hard = 1;
sc_height = 24;
}
/*
* This is terrible - the following if "knows" that it is being
* executed *after* command line and environment options have
* already been parsed. Should it be executed in the main program
* instead?
*/
if ((sc_window <= 0) || (sc_window >= sc_height))
sc_window = sc_height-1;
if (dumb || (sc_width = tgetnum("co")) < 0)
sc_width = 80;
auto_wrap = tgetflag("am");
ignaw = tgetflag("xn");
/*
* Assumes termcap variable "sg" is the printing width of
* the standout sequence, the end standout sequence,
* the underline sequence, the end underline sequence,
* the boldface sequence, and the end boldface sequence.
*/
if ((so_width = tgetnum("sg")) < 0)
so_width = 0;
be_width = bo_width = ue_width = ul_width = se_width = so_width;
/*
* Get various string-valued capabilities.
*/
sp = sbuf;
sc_pad = (dumb) ? NULL : tgetstr("pc", &sp);
if (sc_pad != NULL)
PC = *sc_pad;
sc_init = (dumb) ? NULL : tgetstr("ti", &sp);
if (sc_init == NULL)
sc_init = "";
sc_deinit= (dumb) ? NULL : tgetstr("te", &sp);
if (sc_deinit == NULL)
sc_deinit = "";
sc_eol_clear = (dumb) ? NULL : tgetstr("ce", &sp);
if (hard || sc_eol_clear == NULL || *sc_eol_clear == '\0')
{
cannot("clear to end of line");
sc_eol_clear = "";
}
sc_clear = (dumb) ? NULL : tgetstr("cl", &sp);
if (hard || sc_clear == NULL || *sc_clear == '\0')
{
cannot("clear screen");
sc_clear = "\n\n";
}
sc_move = (dumb) ? NULL : tgetstr("cm", &sp);
if (hard || sc_move == NULL || *sc_move == '\0')
{
/*
* This is not an error here, because we don't
* always need sc_move.
* We need it only if we don't have home or lower-left.
*/
sc_move = "";
}
sc_s_in = (dumb) ? NULL : tgetstr("so", &sp);
if (hard || sc_s_in == NULL)
sc_s_in = "";
sc_s_out = (dumb) ? NULL : tgetstr("se", &sp);
if (hard || sc_s_out == NULL)
sc_s_out = "";
sc_u_in = (dumb) ? NULL : tgetstr("us", &sp);
if (hard || sc_u_in == NULL)
sc_u_in = sc_s_in;
sc_u_out = (dumb) ? NULL : tgetstr("ue", &sp);
if (hard || sc_u_out == NULL)
sc_u_out = sc_s_out;
sc_b_in = (dumb) ? NULL : tgetstr("md", &sp);
if (hard || sc_b_in == NULL)
{
sc_b_in = sc_s_in;
sc_b_out = sc_s_out;
} else
{
sc_b_out = (dumb) ? NULL : tgetstr("me", &sp);
if (hard || sc_b_out == NULL)
sc_b_out = "";
}
sc_visual_bell = (dumb) ? NULL : tgetstr("vb", &sp);
if (hard || sc_visual_bell == NULL)
sc_visual_bell = "";
sc_home = (dumb) ? NULL : tgetstr("ho", &sp);
if (hard || sc_home == NULL || *sc_home == '\0')
{
if (*sc_move == '\0')
{
cannot("home cursor");
/*
* This last resort for sc_home is supposed to
* be an up-arrow suggesting moving to the
* top of the "virtual screen". (The one in
* your imagination as you try to use this on
* a hard copy terminal.)
*/
sc_home = "|\b^";
} else
{
/*
* No "home" string,
* but we can use "move(0,0)".
*/
strcpy(sp, tgoto(sc_move, 0, 0));
sc_home = sp;
sp += strlen(sp) + 1;
}
}
sc_lower_left = (dumb) ? NULL : tgetstr("ll", &sp);
if (hard || sc_lower_left == NULL || *sc_lower_left == '\0')
{
if (*sc_move == '\0')
{
cannot("move cursor to lower left of screen");
sc_lower_left = "\r";
} else
{
/*
* No "lower-left" string,
* but we can use "move(0,last-line)".
*/
strcpy(sp, tgoto(sc_move, 0, sc_height-1));
sc_lower_left = sp;
sp += strlen(sp) + 1;
}
}
/*
* To add a line at top of screen and scroll the display down,
* we use "al" (add line) or "sr" (scroll reverse).
*/
if (dumb)
sc_addline = NULL;
else if ((sc_addline = tgetstr("al", &sp)) == NULL ||
*sc_addline == '\0')
sc_addline = tgetstr("sr", &sp);
if (hard || sc_addline == NULL || *sc_addline == '\0')
{
cannot("scroll backwards");
sc_addline = "";
/* Force repaint on any backward movement */
back_scroll = 0;
}
if (dumb || tgetflag("bs"))
sc_backspace = "\b";
else
{
sc_backspace = tgetstr("bc", &sp);
if (sc_backspace == NULL || *sc_backspace == '\0')
sc_backspace = "\b";
}
if (couldnt)
/* Give him time to read all the "cannot" messages. */
error("");
}
/*
* Below are the functions which perform all the
* terminal-specific screen manipulation.
*/
/*
* Initialize terminal
*/
public void
init()
{
tputs(sc_init, sc_height, putc);
}
/*
* Deinitialize terminal
*/
public void
deinit()
{
tputs(sc_deinit, sc_height, putc);
}
/*
* Home cursor (move to upper left corner of screen).
*/
public void
home()
{
tputs(sc_home, 1, putc);
}
/*
* Add a blank line (called with cursor at home).
* Should scroll the display down.
*/
public void
add_line()
{
tputs(sc_addline, sc_height, putc);
}
/*
* Move cursor to lower left corner of screen.
*/
public void
lower_left()
{
tputs(sc_lower_left, 1, putc);
}
/*
* Ring the terminal bell.
*/
public void
bell()
{
if (quiet == VERY_QUIET)
vbell();
else
putc('\7');
}
/*
* Output the "visual bell", if there is one.
*/
public void
vbell()
{
if (*sc_visual_bell == '\0')
return;
tputs(sc_visual_bell, sc_height, putc);
}
/*
* Clear the screen.
*/
public void
clear()
{
tputs(sc_clear, sc_height, putc);
}
/*
* Clear from the cursor to the end of the cursor's line.
* {{ This must not move the cursor. }}
*/
public void
clear_eol()
{
tputs(sc_eol_clear, 1, putc);
}
/*
* Begin "standout"
*/
public void
so_enter()
{
tputs(sc_s_in, 1, putc);
}
/*
* End "standout".
*/
public void
so_exit()
{
tputs(sc_s_out, 1, putc);
}
/*
* Begin "underline" (hopefully real underlining,
* otherwise whatever the terminal provides).
*/
public void
ul_enter()
{
tputs(sc_u_in, 1, putc);
}
/*
* End "underline".
*/
public void
ul_exit()
{
tputs(sc_u_out, 1, putc);
}
/*
* Begin "bold"
*/
public void
bo_enter()
{
tputs(sc_b_in, 1, putc);
}
/*
* End "bold".
*/
public void
bo_exit()
{
tputs(sc_b_out, 1, putc);
}
/*
* Erase the character to the left of the cursor
* and move the cursor left.
*/
public void
backspace()
{
/*
* Try to erase the previous character by overstriking with a space.
*/
tputs(sc_backspace, 1, putc);
putc(' ');
tputs(sc_backspace, 1, putc);
}
/*
* Output a plain backspace, without erasing the previous char.
*/
public void
putbs()
{
tputs(sc_backspace, 1, putc);
}
SHAR_EOF
fi
if test -f 'signal.c'
then
echo shar: "will not over-write existing file 'signal.c'"
else
cat << \SHAR_EOF > 'signal.c'
/*
* Routines dealing with signals.
*
* A signal usually merely causes a bit to be set in the "signals" word.
* At some convenient time, the mainline code checks to see if any
* signals need processing by calling psignal().
* An exception is made if we are reading from the keyboard when the
* signal is received. Some operating systems will simply call the
* signal handler and NOT return from the read (with EINTR).
* To handle this case, we service the interrupt directly from
* the handler if we are reading from the keyboard.
*/
#include "less.h"
#include <signal.h>
#include <setjmp.h>
/*
* The type of signal handler functions.
* Usually int, although it should be void.
*/
typedef int HANDLER;
/*
* "sigs" contains bits indicating signals which need to be processed.
*/
public int sigs;
#define S_INTERRUPT 01
#ifdef SIGTSTP
#define S_STOP 02
#endif
extern int reading;
extern char *first_cmd;
extern jmp_buf main_loop;
/*
* Interrupt signal handler.
*/
static HANDLER
interrupt()
{
SIGNAL(SIGINT, interrupt);
sigs |= S_INTERRUPT;
if (reading)
psignals();
}
#ifdef SIGTSTP
/*
* "Stop" (^Z) signal handler.
*/
static HANDLER
stop()
{
SIGNAL(SIGTSTP, stop);
sigs |= S_STOP;
if (reading)
psignals();
}
#endif
/*
* Set up the signal handlers.
*/
public void
init_signals()
{
(void) SIGNAL(SIGINT, interrupt);
#ifdef SIGTSTP
(void) SIGNAL(SIGTSTP, stop);
#endif
}
/*
* Process any signals we have recieved.
* A received signal cause a bit to be set in "sigs".
*/
public void
psignals()
{
register int tsignals;
tsignals = sigs;
sigs = 0;
if (tsignals == 0)
return;
dropout(); /* Discard any buffered output */
#ifdef SIGTSTP
if (tsignals & S_STOP)
{
/*
* Clean up the terminal.
*/
#ifdef SIGTTOU
SIGNAL(SIGTTOU, SIG_IGN);
#endif
lower_left();
clear_eol();
flush();
raw_mode(0);
#ifdef SIGTTOU
SIGNAL(SIGTTOU, SIG_DFL);
#endif
SIGNAL(SIGTSTP, SIG_DFL);
#if SIGSETMASK
/*
* This system will not allow us to send a
* stop signal (SIGTSTP) to ourself
* while we are in the signal handler, like maybe now.
* (This can be the case if we are reading; see comment above.)
* So we ask the silly system for permission to do so.
*/
sigsetmask(0);
#endif
kill(getpid(), SIGTSTP);
/*
* ... Bye bye. ...
* Hopefully we'll be back later and resume here...
* Reset the terminal and arrange to repaint the
* screen when we get back to the main command loop.
*/
SIGNAL(SIGTSTP, stop);
raw_mode(1);
first_cmd = "r";
longjmp(main_loop, 1);
}
#endif
if (tsignals & S_INTERRUPT)
{
bell();
/*
* {{ You may wish to replace the bell() with
* error("Interrupt"); }}
*/
}
longjmp(main_loop, 1);
}
/*
* Pass the specified command to a shell to be executed.
* Like plain "system()", but handles resetting terminal modes, etc.
*/
public void
lsystem(cmd)
char *cmd;
{
int inp;
/*
* Print the command which is to be executed.
*/
lower_left();
clear_eol();
puts("!");
puts(cmd);
puts("\n");
/*
* De-initialize the terminal and take out of raw mode.
*/
deinit();
flush();
raw_mode(0);
/*
* Restore signals to their defaults.
*/
SIGNAL(SIGINT, SIG_DFL);
#ifdef SIGTSTP
SIGNAL(SIGTSTP, SIG_DFL);
#endif
/*
* Pass the command to the system to be executed.
*/
inp = dup(0);
close(0);
open("/dev/tty", 0);
system(cmd);
close(0);
dup(inp);
close(inp);
/*
* Reset signals, raw mode, etc.
*/
init_signals();
raw_mode(1);
init();
}
SHAR_EOF
fi
if test -f 'ttyin.c'
then
echo shar: "will not over-write existing file 'ttyin.c'"
else
cat << \SHAR_EOF > 'ttyin.c'
/*
* Routines dealing with getting input from the keyboard (i.e. from the user).
*/
#include "less.h"
/*
* The boolean "reading" is set true or false according to whether
* we are currently reading from the keyboard.
* This information is used by the signal handling stuff in signal.c.
* {{ There are probably some race conditions here
* involving the variable "reading". }}
*/
public int reading;
static int tty;
/*
* Open keyboard for input.
* (Just use file descriptor 2.)
*/
public void
open_getc()
{
tty = 2;
}
/*
* Get a character from the keyboard.
*/
public int
getc()
{
char c;
int result;
reading = 1;
do
{
flush();
result = read(tty, &c, 1);
} while (result != 1);
reading = 0;
return (c & 0177);
}
SHAR_EOF
fi
if test -f 'version.c'
then
echo shar: "will not over-write existing file 'version.c'"
else
cat << \SHAR_EOF > 'version.c'
/*
* less
* Copyright (c) 1984,1985 Mark Nudelman
*
* This program may be freely used and/or modified,
* with the following provisions:
* 1. This notice and the above copyright notice must remain intact.
* 2. Neither this program, nor any modification of it,
* may not be sold for profit without written consent of the author.
*
* -----------------------------------------------------------------
*
* This program is a paginator similar to "more",
* but allows you to move both forward and backward in the file.
* Commands are based on "more" and "vi".
*
* ----------------------- CHANGES ---------------------------------
*
* Allowed use on standard input 1/29/84 markn
* Added E, N, P commands 2/1/84 markn
* Added '=' command, 'stop' signal handling 4/17/84 markn
* Added line folding 4/20/84 markn
* v2: Fixed '=' command to use BOTTOM_PLUS_ONE,
* instead of TOP, added 'p' & 'v' commands 4/27/84 markn
* v3: Added -m and -t options, '-' command 5/3/84 markn
* v4: Added LESS environment variable 5/3/84 markn
* v5: New comments, fixed '-' command slightly 5/3/84 markn
* v6: Added -Q, visual bell 5/15/84 markn
* v7: Fixed jump_back(n) bug: n should count real
* lines, not folded lines. Also allow number
* on G command. 5/24/84 markn
* v8: Re-do -q and -Q commands 5/30/84 markn
* v9: Added "+<cmd>" argument 9/25/84 markn
* v10: Fixed bug in -b<n> argument processing 10/10/84 markn
* v11: Made error() ring bell if \n not entered. 10/18/84 markn
* -----------------------------------------------------------------
* v12: Reorganized signal handling and made
* portable to 4.2bsd. 2/13/85 mark
* v13: Reword error message for '-' command. 2/16/85 mark
* v14: Added -bf and -bp variants of -b. 2/22/85 mark
* v15: Miscellaneous changes. 2/25/85 mark
* v16: Added -u flag for backspace processing. 3/13/85 mark
* v17: Added j and k commands,
* changed -t default. 4/13/85 mark
* v18: Rewrote signal handling code. 4/20/85 mark
* v19: Got rid of "verbose" eq_message(). 5/2/85 mark
* Made search() scroll in some cases.
* v20: Fixed screen.c ioctls for System V. 5/21/85 mark
* v21: Fixed some first_cmd bugs. 5/23/85 mark
* v22: Added support for no RECOMP nor REGCMP. 5/24/85 mark
* v23: Miscellanous changes and prettying up. 5/25/85 mark
* v24: Added ti,te terminal init & de-init 6/3/85 Mike Kersenbrock
* v25: Added -U flag, standout mode underlining. 6/8/85 mark
* v26: Added -M flag. 6/9/85 mark
* Use underline termcap (us) if it exists.
* v27: Renamed some variables to make unique in 6/15/85 mark
* 6 chars. Minor fix to -m.
* v28: Fixed right margin bug. 6/28/85 mark
* v29: Incorporated M.Rose's changes to signal.c 6/28/85 mark
* v30: Fixed stupid bug in argument processing. 6/29/85 mark
* v31: Added -p flag, changed repaint algorithm. 7/15/85 mark
* Added kludge for magic cookie terminals.
* v32: Added cat_file if output not a tty. 7/16/85 mark
* v33: Added -e flag and EDITOR. 7/23/85 mark
* v34: Added -s flag. 7/26/85 mark
* v35: Rewrote option handling; added option.c. 7/27/85 mark
* v36: Fixed -e flag to work if not last file. 7/29/85 mark
* v37: Added -x flag. 8/10/85 mark
* v38: Changed prompting; created prompt.c. 8/19/85 mark
* v39: (Not -p) does not initially clear screen. 8/24/85 mark
* v40: Added "skipping" indicator in forw(). 8/26/85 mark
* v41: ONLY_RETURN, control char commands, 9/17/85 mark
* faster search, other minor fixes.
* v42: Added ++ command line syntax; 9/25/85 mark
* ch_fsize for pipes.
* v43: Added -h flag, changed prim.c algorithms. 10/15/85 mark
* v44: Made END print in all cases of eof; 10/16/85 mark
* ignore SIGTTOU after receiving SIGTSTP.
* v45: Never print backspaces unless -u. 10/16/85 mark
* v46: Backwards scroll in jump_loc. 10/24/85 mark
* v47: Fixed bug in edit(): *first_cmd==0 10/30/85 mark
* v48: Use TIOCSETN instead of TIOCSETP. 11/16/85 mark
* Added marks (m and ' commands).
* -----------------------------------------------------------------
*/
char version[] = "@(#) less version 48";
SHAR_EOF
fi
exit 0
# End of shell archive